import type { Options as TsupOptions } from 'tsup';
import type { ViteDevServer } from 'vite';

import type { AppBuilderOptions } from '../../../typing';

import { spawn } from 'node:child_process';

import { consola } from '@vben/node-utils';

import treeKill from 'tree-kill';
import { build as tsupBuild } from 'tsup';

/**
 * @Description:自定义启动方式
 * @Author: lishibin
 * @Date: 12:19 2022/1/9
 * @version : V0.0.1-beta
 */
export default abstract class Runner {
  config: AppBuilderOptions;

  constructor(cfg: AppBuilderOptions) {
    this.config = cfg;
  }

  async build(tsOpts?: any) {
    this.run(tsOpts);
  }

  async exit() {
    return new Promise((resolve, reject) => {
      if (!process.archaiNexusApp) {
        resolve(true);
        return;
      }
      process.archaiNexusApp.removeAllListeners();
      if (!process.archaiNexusApp.pid) {
        resolve(true);
        return;
      }
      treeKill(process.archaiNexusApp.pid, (err) => {
        if (err) {
          reject(err);
        } else {
          resolve(true);
        }
      });
    });
  }

  getArgs() {
    return ['.'];
  }
  abstract getExec(): any;

  async run(tsOpts: any, server?: ViteDevServer) {
    const { __NAME__: name, onSuccess: _onSuccess, ...tsupOptions } = tsOpts;
    const onSuccess: TsupOptions['onSuccess'] = async () => {
      if (typeof _onSuccess === 'function') {
        await _onSuccess();
      }
      if (!server) {
        return;
      }
      if (name === 'main') {
        consola.success('Main Process Restart Success!');
        await this.runApp();
      } else {
        consola.log(`reload page`);
        server?.ws.send({
          type: 'full-reload',
        });
      }
    };
    await tsupBuild({ onSuccess, ...tsupOptions, watch: 'src/main/*.mts' });
  }

  async runApp() {
    await this.exit();
    consola.ready('Electron App Started...');
    const args = this.getArgs();
    process.archaiNexusApp = spawn(this.getExec(), args, {
      stdio: 'inherit',
      shell: true,
    });
    process.archaiNexusApp.once('exit', process.exit);
    process.once('exit', () => {
      this.exit();
      process.archaiNexusApp.kill();
    });
  }
}
